package com.cs.code.auto;

import com.alibaba.fastjson.JSON;
import com.cs.core.util.FileUtil;
import com.cs.core.util.ParamUtil;
import com.cs.core.util.StringUtil;
import com.cs.code.helper.JdbcHelper;
import com.cs.code.model.CsTable;
import com.cs.code.util.FtlUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * <p>
 *     默认内置
 * </p>
 * @author wind
 * @date    2025/1/22 11:30
 * @version v1.0
 */
public class CodeHelper {

    private static final String AUTHOR = "author";

    private static final String PARENT = "parent";

    private static final String PACKAGE = "package";

    private List<CsTable> tables;

    private JdbcHelper jdbcHelper;

    private final GlobalConfig globalConfig;

    private final PackageConfig packageConfig;

    private final DbConfig dbConfig;

    private CodeHelper(){
        this.globalConfig = new GlobalConfig();
        this.packageConfig = new PackageConfig();
        this.dbConfig = new DbConfig();
    }



    /**
     * 初始化
     * @param jdbcUrl
     * @param username
     * @param password
     * @return
     */
    public static CodeHelper source(String jdbcUrl, String username, String password){
        JdbcHelper jdbcHelper = new JdbcHelper(jdbcUrl, username, password);
        CodeHelper codeHelper = new CodeHelper();
        codeHelper.jdbcHelper = jdbcHelper;
        codeHelper.tables = new ArrayList<>();
        return codeHelper;
    }

    /**
     * 全局配置
     * @param config
     * @return
     */
    public CodeHelper globalConfig(Consumer<GlobalConfig> config){
        if(config != null){
            config.accept(globalConfig);
        }
        return this;
    }

    /**
     * 包配置
     * @param config
     * @return
     */
    public CodeHelper packageConfig(Consumer<PackageConfig> config){
        if(config != null){
            config.accept(packageConfig);
        }
        return this;
    }

    /**
     * 数据库配置
     * @param config
     * @return
     */
    public CodeHelper dbConfig(Consumer<DbConfig> config){
        if(config != null){
            config.accept(dbConfig);
        }
        return this;
    }


    /**
     * 初始化
     */
    private void initTable(){
        String catalog = dbConfig.dbName;
        if(StringUtil.isEmpty(catalog)){
            catalog = jdbcHelper.getCatalog();
        }
        this.tables.addAll(jdbcHelper.getTables(catalog, dbConfig.schema, dbConfig.name));
    }

    /**
     * 生成controller代码
     * @param data
     * @param table
     */
    private void controller(Map<String, Object> data, CsTable table){
        String tplName = "default/controller.ftl";
        String dir = "controller";
        if(StringUtil.isNotBlank(packageConfig.controller)){
            dir = packageConfig.controller;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "Controller.java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }

    /**
     * 生成dao代码
     * @param data
     * @param table
     */
    private void dao(Map<String, Object> data, CsTable table){
        String tplName = "default/dao.ftl";
        String dir = "dao";
        if(StringUtil.isNotBlank(packageConfig.dao)){
            dir = packageConfig.dao;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "Mapper.java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }

    /**
     * 生成model代码
     * @param data
     * @param table
     */
    private void model(Map<String, Object> data, CsTable table){
        String tplName = "default/model.ftl";
        String dir = "entity";
        if(StringUtil.isNotBlank(packageConfig.model)){
            dir = packageConfig.model;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + ".java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }

    /**
     * 生成model代码
     * @param data
     * @param table
     */
    private void extend(Map<String, Object> data, CsTable table){
        String tplName = "default/extend.ftl";
        String dir = "extend";
        if(StringUtil.isNotBlank(packageConfig.extend)){
            dir = packageConfig.extend;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "Extend.java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }



    /**
     * 生成service代码
     * @param data
     * @param table
     */
    private void service(Map<String, Object> data, CsTable table){
        String tplName = "default/service.ftl";
        String dir = "service";
        if(StringUtil.isNotBlank(packageConfig.service)){
            dir = packageConfig.service;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "Service.java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }

    /**
     * 生成impl代码
     * @param data
     * @param table
     */
    private void impl(Map<String, Object> data, CsTable table){
        String tplName = "default/impl.ftl";
        String dir = "service.impl";
        if(StringUtil.isNotBlank(packageConfig.impl)){
            dir = packageConfig.impl;
        }
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "ServiceImpl.java";
        String source = "src/main/java/" + packageName.replaceAll("\\.", "/");
        tplOut(tplName, source, name, data);
    }


    /**
     * 生成impl代码
     * @param data
     * @param table
     */
    private void mapper(Map<String, Object> data, CsTable table){
        String tplName = "default/mapper.ftl";
        String dir = "dao";
        String packageName = getPackage(dir);
        data.put(PACKAGE, packageName);
        String name = table.getProperty() + "Mapper.xml";
        String source = "src/main/resources/mapper";
        tplOut(tplName, source, name, data);
    }

    /**
     * 获取包名
     * @param name
     * @return
     */
    private String getPackage(String name){
        String packageName = "";
        if(StringUtil.isNotBlank(packageConfig.parent)){
            packageName = packageConfig.parent + ".";
        }
        if(StringUtil.isNotBlank(name)){
            packageName += name + ".";
        }
        return packageName.substring(0, packageName.length() - 1);
    }

    /**
     * 输出
     * @param tplName
     * @param dir 路径名称
     * @param name
     * @param data
     */
    private void tplOut(String tplName, String dir, String name, Map<String, Object> data){
        String outDir = globalConfig.outDir;
        String parentDir = outDir + "/" + dir + "/";
        FileUtil.mkdirs(parentDir);
        String filename = parentDir + name;
        FtlUtil.out(tplName, filename, data);
    }

    /**
     * 解析和生成代码
     * @param table
     */
    private void parseTable(CsTable table){
        Map<String, Object> map = JSON.parseObject(JSON.toJSONString(table), Map.class);
        map.put(AUTHOR, globalConfig.author);
        map.put(PARENT, packageConfig.parent);

        controller(map, table);
        dao(map, table);
        model(map, table);
        extend(map, table);
        service(map, table);
        impl(map, table);
        mapper(map, table);
    }

    /**
     * 初始化参数
     */
    private void initParam(){
        if(StringUtil.isEmpty(globalConfig.outDir)){
            globalConfig.outDir(System.getProperty("user.dir"));
        }
        ParamUtil.notEmpty(globalConfig.outDir, "输出文件夹不能为空");
        if(StringUtil.isEmpty(globalConfig.author)){
            globalConfig.author = "";
        }

        if(globalConfig.clear){
            FileUtil.delDir(globalConfig.outDir);
        }
    }



    /**
     * 执行
     */
    public void run(){
        initParam();
        initTable();
        for (CsTable t: tables){
            parseTable(t);
        }
    }


}
